package com.jt.ktdemo.utils

import android.content.Context
import android.content.SharedPreferences
import android.util.Base64
import com.jt.ktdemo.MyApplication
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.io.Serializable
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method

/**
 * Created by SensYang on 2019/02/27 10:32
 */

class SpUtils {
    init {
        /* cannot be instantiated */
        throw UnsupportedOperationException("cannot be instantiated")
    }

    private object SharedPreferencesCompat {
        private val sApplyMethod = findApplyMethod()
        private fun findApplyMethod(): Method? {
            try {
                val clz = SharedPreferences.Editor::class.java
                return clz.getMethod("apply")
            } catch (e: NoSuchMethodException) {
            }

            return null
        }

        fun apply(editor: SharedPreferences.Editor) {
            try {
                if (sApplyMethod != null) {
                    sApplyMethod.invoke(editor)
                    return
                }
            } catch (e: IllegalArgumentException) {
            } catch (e: IllegalAccessException) {
            } catch (e: InvocationTargetException) {
            }

            editor.commit()
        }
    }

    companion object {

        val FILE_NAME = "kotlin_demo"
        fun put(key: String, `object`: Any): String {
            val sp = MyApplication.getInstance().getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
            val editor = sp.edit()

            if (`object` is String) {
                editor.putString(key, `object`)
            } else if (`object` is Int) {
                editor.putInt(key, `object`)
            } else if (`object` is Boolean) {
                editor.putBoolean(key, `object`)
            } else if (`object` is Float) {
                editor.putFloat(key, `object`)
            } else if (`object` is Long) {
                editor.putLong(key, `object`)
            } else {
                editor.putString(key, `object`.toString())
            }

            SpUtils.SharedPreferencesCompat.apply(editor)
            return key
        }


        fun put(context: Context, key: String, `object`: Any): String {

            val sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
            val editor = sp.edit()

            if (`object` is String) {
                editor.putString(key, `object`)
            } else if (`object` is Int) {
                editor.putInt(key, `object`)
            } else if (`object` is Boolean) {
                editor.putBoolean(key, `object`)
            } else if (`object` is Float) {
                editor.putFloat(key, `object`)
            } else if (`object` is Long) {
                editor.putLong(key, `object`)
            } else {
                editor.putString(key, `object`.toString())
            }

            SpUtils.SharedPreferencesCompat.apply(editor)
            return key
        }

        operator fun get(key: String, defaultObject: Any): Any? {
            val sp = MyApplication.getInstance().getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)

            if (defaultObject is String) {
                return sp.getString(key, defaultObject)
            } else if (defaultObject is Int) {
                return sp.getInt(key, defaultObject)
            } else if (defaultObject is Boolean) {
                return sp.getBoolean(key, defaultObject)
            } else if (defaultObject is Float) {
                return sp.getFloat(key, defaultObject)
            } else if (defaultObject is Long) {
                return sp.getLong(key, defaultObject)
            }

            return null
        }

        operator fun get(context: Context, key: String, defaultObject: Any): Any? {
            val sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)

            when (defaultObject) {
                is String -> {
                    return sp.getString(key, defaultObject)
                }
                is Int -> {
                    return sp.getInt(key, defaultObject)
                }
                is Boolean -> {
                    return sp.getBoolean(key, defaultObject)
                }
                is Float -> {
                    return sp.getFloat(key, defaultObject)
                }
                is Long -> {
                    return sp.getLong(key, defaultObject)
                }
                else -> return null
            }

        }

        fun remove(context: Context, key: String) {
            val sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
            val editor = sp.edit()
            editor.remove(key)
            SpUtils.SharedPreferencesCompat.apply(editor)
        }

        fun clear(context: Context) {
            val sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
            val editor = sp.edit()
            editor.clear()
            SpUtils.SharedPreferencesCompat.apply(editor)
        }

        fun contains(context: Context, key: String): Boolean {
            val sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
            return sp.contains(key)
        }

        fun getAll(context: Context): Map<String, *> {
            val sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
            return sp.all
        }

        fun putBean(key: String, obj: Any) {
            putBean(MyApplication.getInstance(), key, obj)
        }

        fun putBean(context: Context, key: String, obj: Any) {
            if (obj is Serializable) {
                try {
                    val baos = ByteArrayOutputStream()
                    val oos = ObjectOutputStream(baos)
                    oos.writeObject(obj)
                    val string64 = String(Base64.encode(baos.toByteArray(),
                            0))
                    val sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
                    val editor = sp.edit()
                    editor.putString(key, string64).commit()
                } catch (e: IOException) {
                    e.printStackTrace()
                }

            } else {
                throw IllegalArgumentException(
                        "the obj must implement Serializble")
            }
        }

        fun getBean(key: String): Any? {
            return getBean(MyApplication.getInstance(), key)
        }

        fun getBean(context: Context, key: String): Any? {
            var obj: Any? = null
            val sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
            try {
                val base64 = sp.getString(key, "")
                if (base64 == "") {
                    return null
                }
                val base64Bytes = Base64.decode(base64!!.toByteArray(), 1)
                val bais = ByteArrayInputStream(base64Bytes)
                val ois = ObjectInputStream(bais)
                obj = ois.readObject()
            } catch (e: Exception) {
                e.printStackTrace()
            }

            return obj
        }
    }

}
